﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using ERPStore.Extensions;
using ERPStore.Exporter.Models;

using CloudSoft.Extensions;

namespace ERPStore.Exporter.Services
{
	public class ExporterService : ERPStore.Exporter.Services.IExporterService
	{
		public ExporterService(CloudSoft.Repositories.IRepository<Repositories.ExporterDbContext> exporterRepository
			, ERPStore.Services.CryptoService cryptoService)
		{
			this.ExporterRepository = exporterRepository;
			this.CryptoService = cryptoService;
		}

		protected CloudSoft.Repositories.IRepository<Repositories.ExporterDbContext> ExporterRepository { get; private set; }
		protected ERPStore.Services.CryptoService CryptoService { get; private set; }

		private IQueryable<Repositories.Datas.BanishedProductBySource> GetAllBanishedProduct()
		{
			var result = ExporterRepository.Query<Repositories.Datas.BanishedProductBySource>();

			return result;
		}

		public IEnumerable<int> GetBanishedProductBySourceId(string sourceId)
		{
			var list = GetBanishedProductListBySourceId(sourceId);

			return list.Where(i => i.ReleaseDate == null || i.ReleaseDate > DateTime.Today).Select(i => i.ProductId);
		}

		public Models.BanishedProduct CreateBanishedProduct()
		{
			var result = new Models.BanishedProduct();
			result.CreationDate = DateTime.Now;
			return result;
		}

		public IEnumerable<Models.BanishedProduct> GetBanishedProductListByFilter(Models.BanishedProductListFilter filter, out int count)
		{
			var list = GetAllBanishedProduct();

			if (filter.HasReleaseDate.HasValue)
			{
				list = list.Where(i => i.ReleaseDate.HasValue);
			}

			if (filter.ProductId.HasValue)
			{
				list = list.Where(i => i.ProductId == filter.ProductId.Value);
			}

			if (filter.SourceId != null)
			{
				list = list.Where(i => i.SourceId == filter.SourceId);
			}

			if (!filter.SortColumnName.IsNullOrTrimmedEmpty())
			{
				if (filter.SortDirection == System.ComponentModel.ListSortDirection.Ascending)
				{
					list = list.OrderBy(filter.SortColumnName);
				}
				else
				{
					list = list.OrderByDescending(filter.SortColumnName);
				}
			}
			else
			{
				list = list.OrderBy(i => i.Id);
			}

			count = list.Count();
			var pagedList = list.Skip(filter.PageIndex * filter.PageSize).Take(filter.PageSize).ToList();
			var result = new List<Models.BanishedProduct>();
			foreach (var item in pagedList)
			{
				result.Add(item.ToBanishedProduct());
			}
			return result;
		}

		public void SaveBanishedProducList(IEnumerable<Models.BanishedProduct> banishedProductList)
		{
			if (banishedProductList == null)
			{
				return;
			}
			foreach (var item in banishedProductList)
			{
				SaveBanishedProduct(item);
			}
		}

		public void SaveBanishedProduct(Models.BanishedProduct item)
		{
			var data = ExporterRepository.Get<Repositories.Datas.BanishedProductBySource>(i => i.ProductId == item.ProductId && i.SourceId == item.SourceId);
			bool isNewRecord = false;
			if (data == null)
			{
				if (item.SourceId != "all")
				{
					// On verifie si le produit n'est pas globalement blacklisté
					data = ExporterRepository.Get<Repositories.Datas.BanishedProductBySource>(i => i.SourceId == item.SourceId && i.SourceId == "all");
					if (data == null)
					{
						data = new Repositories.Datas.BanishedProductBySource();
						isNewRecord = true;
					}
					else
					{
						item.SourceId = "all";
					}
				}
				else
				{
					data = new Repositories.Datas.BanishedProductBySource();
					isNewRecord = true;
				}
			}
			data.ProductId = item.ProductId;
			data.SourceId = item.SourceId;
			data.ReleaseDate = item.ReleaseDate;
			data.CreationDate = item.CreationDate;

			// Si la date est dépassé on supprime 
			if (data.ReleaseDate.HasValue
				&& data.ReleaseDate <= DateTime.Today)
			{
				ExporterRepository.Delete(data);
				return;
			}

			if (isNewRecord)
			{
				ExporterRepository.Insert(data);
			}
			else
			{
				ExporterRepository.Update(data);
			}

		}

		public void DeleteBanishedProductList(IEnumerable<Models.BanishedProduct> banishedProductList)
		{
			if (banishedProductList == null)
			{
				return;
			}
			foreach (var item in banishedProductList)
			{
				var data = ExporterRepository.Get<Repositories.Datas.BanishedProductBySource>(i => i.ProductId == item.ProductId && i.SourceId == item.SourceId);
				if (data == null)
				{
					if (item.SourceId != "all")
					{
						// On verifie si le produit n'est pas globalement blacklisté
						data = ExporterRepository.Get<Repositories.Datas.BanishedProductBySource>(i => i.SourceId == item.SourceId && i.SourceId == "all");
						if (data == null)
						{
							continue;
						}
					}
					else
					{
						continue;
					}
				}

				ExporterRepository.Delete(data);
			}
			
		}

		public IDictionary<int, int> GetBanishmentCountByProductIdList(IEnumerable<int> productIdList)
		{
			var maxDate = DateTime.MaxValue;
			var data = from banishment in ExporterRepository.Query<Repositories.Datas.BanishedProductBySource>()
					   let releaseDate = banishment.ReleaseDate ?? maxDate
					   where productIdList.Contains(banishment.ProductId)
							 && releaseDate >= DateTime.Today
					   group banishment by banishment.ProductId into g
					   select new 
					   {
						   ProductId = g.Key,
						   Count = g.Count()
					   };

			var result = data.ToDictionary(k => k.ProductId, v => v.Count);
			return result;
		}

		public string BuildEncryptedProductUrl(ERPStore.Models.LeadSourceBase leadSource, ERPStore.Models.Product product)
		{
			var key = BuildEncryptedProductKey(leadSource, product);
			var result = string.Format("http://{0}/cp/trk/{1}"
				, GlobalConfiguration.Configuration.Settings.DefaultUrl
				, key);

			return result;
		}

		public string BuildEncryptedProductKey(ERPStore.Models.LeadSourceBase leadSource, ERPStore.Models.Product product)
		{
			var tk = new Models.TrackKey();
			tk.Date = string.Format("{0:yyMMdd}", DateTime.Now);
			tk.Medium = leadSource.Medium;
			tk.ProductCode = product.EncodedCode();
			tk.SourceId = leadSource.Id;
			tk.SourceName = leadSource.TrackSourceId.ToLower();
			var key = CryptoService.Encrypt(tk);
			return key;
		}

		public string BuildProductUrl(ERPStore.Models.LeadSourceBase leadSource, ERPStore.Models.Product product)
		{
			var result = string.Format("http://{0}/produit/{1}/{2}/?estid={3}&utm_source={3}&estcd={4:yyMMdd}&utm_medium={5}"
				, GlobalConfiguration.Configuration.Settings.DefaultUrl
				, product.EncodedCode()
				, product.Link
				, leadSource.TrackSourceId
				, DateTime.Now
				, leadSource.Medium);

			return result;
		}


		public void DropBanishedExpiration()
		{
			var query = ExporterRepository.Query<Repositories.Datas.BanishedProductBySource>()
						.Where(i => i.ReleaseDate.HasValue && i.ReleaseDate.Value < DateTime.Now);

			var list = query.ToList();
			foreach (var item in list)
			{
				ExporterRepository.Delete<Repositories.Datas.BanishedProductBySource>(item);
			}
		}

		#region Data Access

		public IEnumerable<Models.BanishedProduct> GetBanishedProductListBySourceId(string sourceId)
		{
			if (sourceId == null)
			{
				return null;
			}
			var list = ExporterRepository.Query<Repositories.Datas.BanishedProductBySource>(i => i.SourceId == sourceId || i.SourceId == "all");
			var result = new List<Models.BanishedProduct>();
			if (list != null)
			{
				foreach (var item in list)
				{
					result.Add(item.ToBanishedProduct());
				}
			}
			return result;
		}

		public void DeleteBanishedProduct(Models.BanishedProduct model)
		{
			var existing = ExporterRepository.Get<Repositories.Datas.BanishedProductBySource>(i => i.SourceId == model.SourceId && i.ProductId == model.ProductId);
			if (existing != null)
			{
				ExporterRepository.Delete(existing);
			}
		}


		#endregion
	}
}
